<script setup lang="ts">
import { onMounted } from "vue";

let selection: Selection | null = null;

onMounted(() => {
  document.addEventListener("selectionchange", () => {
    const innerSelection = window.getSelection();

    const isInEditor =
      innerSelection?.focusNode &&
      document
        .querySelector(".editor-content")
        ?.contains(innerSelection?.focusNode);

    console.log(
      "🚀 ~ document.addEventListener ~ innerSelection?.focusNode:",
      innerSelection,
      innerSelection?.focusNode,
      document.querySelector(".editor-content")
    );

    if (!isInEditor) {
      return;
    }
    selection = innerSelection;

    console.log("🚀 ~ document.addEventListener ~ isInEditor:", isInEditor);
    console.log("🚀 ~ editorContent.addEventListener ~ selection:", selection);
    if (!selection) return;
    const range = selection.getRangeAt(0);
    console.log("🚀 ~ selectionchange ~ range:", range);
  });
});

// 检查当前选区是否已被包装
// function isWrapped(range, command) {
//   let container = range.commonAncestorContainer;
//   if (container.nodeType === Node.TEXT_NODE) {
//     container = container.parentNode;
//   }

//   switch (command) {
//     case "bold":
//       return container.nodeName === "B";
//     case "italic":
//       return container.nodeName === "I";
//     case "underline":
//       return container.nodeName === "U";
//     default:
//       return false;
//   }
// }
// 检查当前选区是否已被包装
function isWrapped(range, command) {
  let container = range.commonAncestorContainer;

  if (container.nodeType === Node.TEXT_NODE) {
    container = container.parentNode;
  }

  // 遍历父节点，检查是否有指定格式的节点
  while (container && container !== document) {
    switch (command) {
      case "bold":
        if (container.nodeName === "B" || container.nodeName === "STRONG")
          return true;
        break;
      case "italic":
        if (container.nodeName === "I" || container.nodeName === "EM")
          return true;
        break;
      case "underline":
        if (container.nodeName === "U") return true;
        break;
      case "color":
        if (container.nodeName === "SPAN" && container.style.color) return true;
        break;
      default:
        return false;
    }
    container = container.parentNode;
  }
  return false;
}

// 移除包装节点
// function unwrap(range, command) {
//   let container = range.commonAncestorContainer;
//   if (container.nodeType === Node.TEXT_NODE) {
//     container = container.parentNode;
//   }

//   if (
//     (command === "bold" && container.nodeName === "B") ||
//     (command === "italic" && container.nodeName === "I") ||
//     (command === "underline" && container.nodeName === "U")
//   ) {
//     const parent = container.parentNode;
//     while (container.firstChild) {
//       parent.insertBefore(container.firstChild, container);
//     }
//     parent.removeChild(container);
//   }
// }
// 移除包装节点
function unwrap(range, command) {
  let container = range.commonAncestorContainer;
  if (container.nodeType === Node.TEXT_NODE) {
    container = container.parentNode;
  }

  function unwrapNode(node) {
    if (!node) return;

    const parentNode = node.parentNode;
    if (!parentNode) return;

    // 判断当前节点是否是要移除的格式化标签
    if (
      (command === "bold" &&
        (node.nodeName === "B" || node.nodeName === "STRONG")) ||
      (command === "italic" &&
        (node.nodeName === "I" || node.nodeName === "EM")) ||
      (command === "underline" && node.nodeName === "U") ||
      (command === "color" && node.nodeName === "SPAN" && node.style.color)
    ) {
      // 处理拆分选区前的部分
      const beforeRange = document.createRange();
      beforeRange.setStartBefore(node);
      beforeRange.setEnd(range.startContainer, range.startOffset);

      // 处理拆分选区后的部分
      const afterRange = document.createRange();
      afterRange.setStart(range.endContainer, range.endOffset);
      afterRange.setEndAfter(node);

      // 如果选区之前有内容，插入这些内容
      if (!beforeRange.collapsed) {
        const beforeNode = document.createDocumentFragment();
        beforeNode.appendChild(beforeRange.extractContents());
        parentNode.insertBefore(beforeNode, node);
      }

      // 如果选区之后有内容，插入这些内容
      if (!afterRange.collapsed) {
        const afterNode = document.createDocumentFragment();
        afterNode.appendChild(afterRange.extractContents());
        parentNode.insertBefore(afterNode, node.nextSibling);
      }

      // 只保留选中的内容，不包裹在原格式节点内
      const selectedContents = range.extractContents();
      parentNode.insertBefore(selectedContents, node);

      // 移除原格式节点
      parentNode.removeChild(node);
    } else {
      unwrapNode(node.parentNode); // 递归处理父节点
    }
  }

  unwrapNode(container);
}

// function exec(command: string, extra?: any) {
//   if (!selection) return;
//   // 清除所有选取
//   // selection.removeAllRanges();
//   const range = selection.getRangeAt(0);
//   // 处理
//   const selectedText = range.extractContents();
//   // const selectedText = range.cloneContents();
//   console.log("🚀 ~ exec ~ selection:", selection);
//   console.log("🚀 ~ exec ~ range:", range);
//   console.log("🚀 ~ exec ~ selectedText:", selectedText, range.cloneContents());

//   // 将选中内容放置到容器
//   let wrapper;

//   const isContentWrapped = isWrapped(range, command);
//   console.log("🚀 ~ exec ~ isContentWrapped:", isContentWrapped);

//   if (isContentWrapped) {
//     unwrap(range, command);
//     return;
//   }

//   switch (command) {
//     case "bold":
//       wrapper = document.createElement("strong");
//       break;
//     case "italic":
//       wrapper = document.createElement("em");
//       break;
//     case "underline":
//       wrapper = document.createElement("u");
//       break;
//     case "color":
//       wrapper = document.createElement("span");
//       wrapper.style.color = extra.color;
//       break;
//     default:
//       break;
//   }

//   if (!wrapper) return;

//   wrapper.appendChild(selectedText);
//   range.insertNode(wrapper);

//   // 看是否需要更新光标位置
// }

function exec(command: string, extra?: any) {
  if (!selection) return;

  const range = selection.getRangeAt(0);
  const isContentWrapped = isWrapped(range, command);

  if (isContentWrapped) {
    unwrap(range, command); // 如果已被包裹，解除格式
  } else {
    // 如果没有被包裹，则应用新格式
    let wrapper;
    switch (command) {
      case "bold":
        wrapper = document.createElement("strong");
        break;
      case "italic":
        wrapper = document.createElement("em");
        break;
      case "underline":
        wrapper = document.createElement("u");
        break;
      case "color":
        wrapper = document.createElement("span");
        wrapper.style.color = extra.color;
        break;
      default:
        break;
    }

    if (!wrapper) return;

    const selectedText = range.extractContents();
    wrapper.appendChild(selectedText);
    range.insertNode(wrapper);

    // 合并相邻的相同格式标签
    mergeAdjacentNodes(wrapper);
  }

  // 保持选区的位置
  updateSelectionAfterCommand(range);
}

// 合并相邻的相同格式标签
function mergeAdjacentNodes(node) {
  // 检查前一个兄弟节点
  let prevSibling = node.previousSibling;
  while (prevSibling && prevSibling.nodeType !== Node.ELEMENT_NODE) {
    prevSibling = prevSibling.previousSibling;
  }

  if (prevSibling && prevSibling.nodeName === node.nodeName) {
    // 将当前节点的内容合并到前一个兄弟节点中
    while (node.firstChild) {
      prevSibling.appendChild(node.firstChild);
    }
    node.parentNode.removeChild(node); // 移除当前节点
    node = prevSibling; // 更新当前节点为合并后的节点
  }

  // 检查下一个兄弟节点
  let nextSibling = node.nextSibling;
  while (nextSibling && nextSibling.nodeType !== Node.ELEMENT_NODE) {
    nextSibling = nextSibling.nextSibling;
  }

  if (nextSibling && nextSibling.nodeName === node.nodeName) {
    // 将下一个兄弟节点的内容合并到当前节点中
    while (nextSibling.firstChild) {
      node.appendChild(nextSibling.firstChild);
    }
    nextSibling.parentNode.removeChild(nextSibling); // 移除下一个兄弟节点
  }
}

// 更新选区位置以保持用户原始选区
function updateSelectionAfterCommand(range) {
  if (!selection) return;

  selection.removeAllRanges();

  const newRange = document.createRange();
  newRange.setStart(range.startContainer, range.startOffset);
  newRange.setEnd(range.endContainer, range.endOffset);

  selection.addRange(newRange);
}
</script>

<template>
  <div class="editor-wrapper">
    <div>
      <button @click="exec('bold')">加粗</button>
      <button @click="exec('italic')">斜体</button>
      <button @click="exec('underline')">下划线</button>
      <button @click="exec('color', { color: '#f00' })">红色</button>
      <button @click="exec('color', { color: '#0f0' })">绿色</button>
      <input
        type="color"
        @input="(ev) => exec('color', { color: ev.target.value })"
      />
    </div>
    <div class="editor-content" contenteditable="true">
      <p>
        欢迎大家，来到妙码学院，这可能是最细致入微的富文本编辑器架构与编译详解公开课...
      </p>
    </div>
  </div>
</template>

<style scoped>
.editor-wrapper {
  width: 100%;
  height: 100%;
}
.editor-content {
  width: 100%;
  height: 100%;
  padding: 10px;
  outline: none;
  border: 1px solid transparent;
  border-radius: 5px;
  &:focus {
    border: 1px solid #ccc;
  }
}
</style>
